:- module(coverage).
:- export result / 0.
:- export result_body / 3.
:- export result / 2.
:- export result_body / 2.
:- export result / 1.
:- export ccompile_body / 3.
:- export ccompile / 2.
:- export ccompile_body / 2.
:- export ccompile / 1.
:- export point / 2.
:- export point / 1.
:- export print_counters / 0.
:- export reset_counters / 0.
:- comment(author, "Joachim Schimpf, based on ideas by Helmut Simonis").
:- comment(copyright, "Imperial College London and Parc Technologies Ltd").
:- comment(date, "$Date: 2004/11/29 09:55:58 $").
:- comment(summary, "Tool for obtaining code coverage information").
:- comment(desc, html("<P>\r\n\tThis is a tool for obtaining code coverage information, i.e.\r\n\tinformation about which points in the code were executed how\r\n\toften during a particular run of the program.\r\n</P><P>\r\n\tThe usage is as follows:\r\n\t<OL>\r\n\t<LI>Load the coverage library\r\n\t<PRE>\r\n\t?- lib(coverage).\r\n\t</PRE>\r\n\t<LI>Compile your program with the coverage compiler\r\n\t<PRE>\r\n\t?- coverage:ccompile(my_program).\r\n\t</PRE>\r\n\t<LI>Run the query which you want to examine\r\n\t<PRE>\r\n\t?- my_query(X,Y,Z).\r\n\t</PRE>\r\n\t<LI>Generate an html file containing the results. E.g. the following\r\n\twill create the result file coverage/my_program.html:\r\n\t<PRE>\r\n\t?- coverage:result(my_program).\r\n\t</PRE>\r\n\t<LI>View the result file using any browser. The result file\r\n\tcontains a pretty-printed form of the source, annotated with\r\n\tthe values of the code coverage counters.\r\n\t</OL>\r\n</P><P>\r\n\tBy default, code coverage counters are inserted before and after\r\n\tevery subgoal in the code. For instance, in the clause\r\n<PRE>\r\n\tp :- q, r, s.\r\n</PRE>\r\n\tfour counters would be inserted: before the call to q, between\r\n\tq and r, between r and s, and after s:\r\n<PRE>\r\n\tp :- point(1), q, point(2), r, point(3), s, point(4).\r\n</PRE>\r\n\tThis is the most precise form provided. The counter values do not\r\n\tonly show whether all code points were reached, they also show whether\r\n\tsubgoals ever failed or aborted (in that case the counter before\r\n\ta subgoal will have a higher value than the counter after it).\r\n\tFor example, the result of running the above code may look like:\r\n<PRE>\r\n\tp :- <span style=\"color:black; font-weight:bold; background-color:limegreen\"> 43 </span> q, <span style=\"color:black; font-weight:bold; background-color:limegreen\"> 25 </span> r, <span style=\"color:black; font-weight:bold; background-color:limegreen\"> 25 </span> s <span style=\"color:black; font-weight:bold; background-color:red\"> 0 </span>.\r\n</PRE>\r\n\twhich would indicate that q was called 43 times, but succeeded\r\n\tonly 25 times, r was called 25 times and succeeded always, and\r\n\ts was called 25 times and never succeeded.  Coverage counts of\r\n\tzero are displayed in red because they indicate unreached code.\r\n</P><P>\r\n\tIf one is only interested in knowing whether all code was covered,\r\n\tit is not necessary to have all these counters. point(1) and point(4)\r\n\tare enough to know whether q, r and s were successfully executed.\r\n\tThe option <B>blocks_only</B> implements this: counters only\r\n\tget inserted at the beginning and at the end of conjunctions\r\n\t(comma-separated goal sequences), i.e. in the example:\r\n<PRE>\r\n\tp :- point(1), q, r, s, point(4).\r\n</PRE>\r\n\tFor big programs, the presence of counters at the end of\r\n\tclauses can cause problems because they prevent tail-recursion\r\n\toptimization and may lead to stack overflows.  If that should\r\n\tbe the case, exit-counters can be disabled by setting the\r\n\t<B>exit_counters</B> option to <B>off</B>, leading to the following\r\n\tincomplete instrumentation:\r\n<PRE>\r\n\tp :- point(1), q, point(2), r, point(3), s.\r\n</PRE>\r\n</P><P>\r\n\tNote on the analysis of large, structured applications: \r\n\tLarger applications often consist of several modules which get\r\n\tcompiled implicitly through use_module/1 directives.  In this\r\n\tcase, the module(s) that one wants to compile in coverage mode\r\n\tcan be either compiled with ccompile/1 in advance (before\r\n\tloading the main application module), or afterwards (in which\r\n\tcase ccompile/1 will replace the previously compiled normal\r\n\tcode with coverage-code).\r\n</P><P>\r\n\tLimitation: The current implementation cannot deal with multiple\r\n\t(non-module) files that are ccompiled into the same module.\r\n</P>")).
:- comment(ccompile / 1, [summary : "Compile a file, inserting code coverage counters", args : ["File" : "Atom or string"], amode : ccompile(+), see_also : [ccompile / 2, library(coverage), result / 1, result / 2], desc : html("\r\n    This is a variant of the ECLiPSe compiler that inserts code coverage\r\n    counters into the compiled code. This code can then be run, and the\r\n    results analysed by printing them using coverage:result/1.\r\n    ")]).
:- comment(ccompile / 2, [summary : "Compile a file, inserting code coverage counters", args : ["File" : "Atom or string", "OptionList" : "List of Name:Value pairs"], amode : ccompile(+, +), see_also : [ccompile / 1, library(coverage), result / 1, result / 2], desc : html("<P>\r\n    This is a variant of the ECLiPSe compiler that inserts code coverage\r\n    counters into the compiled code. This code can then be run, and the\r\n    results analysed by printing them using coverage:result/1.\r\n</P><P>\r\n    Options to modify the behaviour of the code coverage library are:\r\n<DL>\r\n    <DT>exit_counters (default:on)<DD>\r\n    \tSetting this to 'off' will suppress coverage counters at the end of\r\n\tconjunctions (comma-sequences of subgoals).\r\n    <DT>blocks_only (default:off)<DD>\r\n    \tSetting this to 'on' will leave only coverage counters at the\r\n\tbeginning and at the end of conjunctions (comma-sequences of\r\n\tsubgoals) and suppress all others.\r\n    <DT>macro_expansion (default:off)<DD>\r\n\tThis options affects only the printing of the result (html) file.\r\n\tBy default, read-macros are not expanded in this output.  In rare\r\n\tcases, where macro expansion would affect the placement of coverage\r\n\tcounter positions, it may be necessary to set this option to 'on'\r\n\tin order to display the counter values at the correct positions\r\n\tin the code.\r\n    <DT>goal_expansion (default:on)<DD>\r\n    \tSetting this to 'off' will suppress goal expansion (inlining)\r\n\tduring compilation. This may be necessary when the processed\r\n\tcode contains predicates that get executed at compile time.\r\n    <DT>verbose (default:off)<DD>\r\n    \tIf set to 'on', the coverage preprocessor will print predicate\r\n\tnames as they are processed (to log_output).\r\n</DL>\r\n</P>\r\n    ")]).
:- comment(reset_counters / 0, [summary : "Reset all the coverage counters to zero", args : [], see_also : [ccompile / 1, result / 1], desc : html("\r\n    The system maintains code coverage counters for all code compiled\r\n    with coverage:ccompile/1. These counters get incremented when this\r\n    code is run, and get reset implicitly when the results are output\r\n    using coverage:result/1.\r\n    ")]).
:- comment(result / 0, [summary : "Pretty-print all files with code coverage results", args : [], see_also : [result / 1, result / 2, library(coverage), library(pretty_printer), ccompile / 1], desc : html("<P>\r\n    This will pretty-print all source files that have been previously\r\n    compiled with ccompile/1,2. For details see result/1.\r\n</P>\r\n    ")]).
:- comment(result / 1, [summary : "Pretty-print a file, including any code coverage results", args : ["File" : "Atom or string"], amode : result(+), see_also : [result / 2, library(coverage), library(pretty_printer), ccompile / 1], desc : html("<P>\r\n    This will pretty-print the given source file, annotated with the\r\n    values of code coverage counters. The resulting .html file will be\r\n    placed in a sub-directory called 'coverage', relative to File.\r\n    See result/2 for options to modify the output.\r\n</P><P>\r\n    This predicate only makes sense if File has previously been compiled\r\n    in coverage mode (using coverage:ccompile/1,2), and the code has been\r\n    run in order to obtain values for the coverage counters.\r\n</P>\r\n    ")]).
:- comment(result / 2, [summary : "Pretty-print a file, including any code coverage results", args : ["File" : "Atom or string", "OptionList" : "List of Name:Value pairs"], amode : result(+, +), see_also : [result / 1, pretty_printer : pretty_print / 2, ccompile / 1, library(coverage), library(pretty_printer)], desc : html("<P>\r\n    This will pretty-print the given source file, annotated with the\r\n    values of code coverage counters. By default, the resulting .html\r\n    file will be placed in a sub-directory called 'coverage', relative\r\n    to File.\r\n</P><P>\r\n    OptionList is a list of options identical to the one accepted by\r\n    pretty_print/2 in the library(pretty_printer), and can be used to\r\n    modify the output style and the location of the output file.\r\n</P><P>\r\n    This predicate only makes sense if File has previously been compiled\r\n    in coverage mode (using coverage:ccompile/1,2), and the code has been\r\n    run in order to obtain values for the coverage counters.\r\n    ")]).
:- comment(result_body / 3, hidden).
:- comment(result_body / 2, hidden).
:- comment(ccompile_body / 3, hidden).
:- comment(ccompile_body / 2, hidden).
:- comment(point / 2, hidden).
